#include "cmdinstance.h"
#include "commmsg.h"
#include "commclass.h"
#include "../cmd/dataprepare.h"
#include "../mainctrl.h"
#include "../instance/CInstanceMgr.h"
#include "../item/CDropItem.h"
#include "../clan/CClanMgr.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_GOTO_INSTANCE, CCmdGotoInstance);

int CCmdGotoInstance::Do(void* pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_GOTO_INSTANCE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_GOTO_INSTANCE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdGotoInstance::LogicDo(int iRet)
{
    unsigned char ucInstanceType = (unsigned char)(stReq.ins_type() & 0x7F);
    unsigned short usInstanceID = (unsigned short)(stReq.ins_id() & 0x7FFF);

    int iIndex = 0;
    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_INSTANCE_ZONE_DETAIL_INFO(this, CInstanceZoneDetailInfo::GetKey(ucInstanceType, usInstanceID));
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user player base info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stInstanceZoneDetailInfoHash.HashFind(CInstanceZoneDetailInfo::GetKey(ucInstanceType, usInstanceID));
    if (iIndex < 0)
    {
        CT_ERROR((""));
        return AnsClients(RET_SYS_ERROR);
    }
    CInstanceZoneDetailInfo& stInstanceZoneDetailInfo = pstMainCtrl->m_stInstanceZoneDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];
    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    //检查是否可以攻打该副本
    if (CInstanceConfigData::IsSecret(ucInstanceType)) //攻打秘境有自己的协议
    {
        return AnsClients(RET_SYS_ERROR);
    }

    if (CInstanceConfigData::IsElite(ucInstanceType)
        && stPlayerOnlineData._stUserInstance._stInstanceData._stEliteAtkStat.IsAtkWin(ucInstanceType - CInstanceConfigData::INSTANCE_TYPE_ELITE_BEGIN, usInstanceID, pstMainCtrl->m_iNow)) //精英副本有攻打次数限制
    {
        return AnsClients(ERROR_INSTANCE_ELITE_HAS_ATK);
    }

    //检查系统是否开启
    short usRoleLevel = 0;
    pstMainCtrl->m_stRoleMgr.GetRoleLevel(stReq.gid(), usRoleLevel);
    if (CInstanceConfigData::IsMuseum(ucInstanceType))
    {
        if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_21, stPlayerBaseInfo, stPlayerOnlineData))
        {
            return AnsClients(ERROR_SYS_NOT_OPEN);
        }
    }
    else if (CInstanceConfigData::IsElite(ucInstanceType))
    {
        if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_30, stPlayerBaseInfo, stPlayerOnlineData))
        {
            return AnsClients(ERROR_SYS_NOT_OPEN);
        }
    }
    
    
    //清空地表
    stPlayerOnlineData._stUserGroudBag.SetEmpty();

    //进入副本
    iRet = pstMainCtrl->m_stInstanceMgr.GoIntoInstance(stPlayerOnlineData._stUserInstance, stPlayerOnlineData._stUserTask, 
        ucInstanceType, usInstanceID);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    //需设置所在位置, 已打过的不能打
    if (CInstanceConfigData::IsMuseum(ucInstanceType))
    {
        pstMainCtrl->m_stInstanceMgr.GetOpenStat(stUserInstance, stPlayerOnlineData._stUserTask, ucInstanceType, stUserInstance._usNowAtInstanceID);

        CInstanceDetailStatData stDetailStat;
        pstMainCtrl->m_stInstanceMgr.GetInstanceDetailStat(stUserInstance, ucInstanceType, stDetailStat);
        stUserInstance._usNowPos = stDetailStat.ucNowAccomplishPos;
    }

    //获取怪物队伍列表
    CInstanceMgr::T_INSTANCE_MONSTER_GROUP_IDS astMonsterGroupIDs;
    iRet = pstMainCtrl->m_stInstanceMgr.GetMonsterGroupList(stPlayerOnlineData._stUserInstance, astMonsterGroupIDs);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    for (int i = 0; i < astMonsterGroupIDs.Size(); ++i)
    {
        stAns.add_monster_group_id((int)astMonsterGroupIDs[i]);
    }

    //获取副本详细信息
    for (int i = 0; i < stInstanceZoneDetailInfo._astNewKillEnemyVideos.Size(); ++i)
    {
        stAns.add_video_list(stInstanceZoneDetailInfo._astNewKillEnemyVideos[i]());
    }
    stAns.set_first_kill_role_name(stInstanceZoneDetailInfo._szFirstKillRoleName());
    stAns.set_best_kill_role_name(stInstanceZoneDetailInfo._szBestKillRoleName());

    pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_120* 1000 + stUserInstance._usNowAtInstanceID, 1);

    return AnsClients(iRet);
}

int CCmdGotoInstance::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_ATK_INSTANCE, CCmdAtkInstance);

int CCmdAtkInstance::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_ATK_INSTANCE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_ATK_INSTANCE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdAtkInstance::LogicDo(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    ASSERT_PLAYER_PREPARED(uiGID);

    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    ASSERT_PLAYER_DETAIL_PREPARED(uiGID);

    PREPARE_PLAYER_DETAIL_EX1_INFO(this, uiGID);
    ASSERT_PLAYER_DETAIL_EX1_INFO(uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];
    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    int iInstanceDetailInfoKey = CInstanceZoneDetailInfo::GetKey(stUserInstance._ucNowAtInstanceType, stUserInstance._usNowAtInstanceID);
    PREPARE_INSTANCE_ZONE_DETAIL_INFO(this, iInstanceDetailInfoKey);
    iIndex = pstMainCtrl->m_stInstanceZoneDetailInfoHash.HashFind(iInstanceDetailInfoKey);
    if (iIndex < 0)
    {
        CT_ERROR((""));
        return AnsClients(RET_SYS_ERROR);
    }
    CInstanceZoneDetailInfo& stInstanceZoneDetailInfo = pstMainCtrl->m_stInstanceZoneDetailInfoHash[iIndex];

    //检查是否可攻击
    if (CInstanceConfigData::IsMuseum(stUserInstance._ucNowAtInstanceType)) //博物馆副本，已战胜过的不能再打，只能扫荡
    {
        if (!pstMainCtrl->m_stInstanceMgr.IsMuseumCanAtk(stUserInstance))
        {
            return AnsClients(ERROR_INSTANCE_MUSEUM_CAN_NOT_ATK_EMEMY);
        }
    }

    //获取怪物列表
    CMonsterGroupConfigData stMonsterGroupConfigData;
    iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroup(stPlayerOnlineData._stUserInstance, stMonsterGroupConfigData);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    CInstanceConfigData stInstanceConfigData;
    iRet = pstMainCtrl->m_stInstanceMgr.GetConfigData(stUserInstance._ucNowAtInstanceType, stUserInstance._usNowAtInstanceID, stInstanceConfigData);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    stAns.set_ins_type(stPlayerOnlineData._stUserInstance._ucNowAtInstanceType);
    stAns.set_ins_id(stPlayerOnlineData._stUserInstance._usNowAtInstanceID);
    stAns.set_now_atk_pos(stInstanceConfigData._astMonsterGroupPos[stPlayerOnlineData._stUserInstance._usNowPos]);

    MsgBattleResult* pstMsgBattleResult = stAns.mutable_battle_result();
	if (pstMsgBattleResult && stReq.has_ext_info())
	{
		(*pstMsgBattleResult->mutable_battle_ext_info()) = stReq.ext_info();
	}
    iRet = pstMainCtrl->m_stBattleMgr.DealBattle(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, 
                            stMonsterGroupConfigData, *pstMsgBattleResult, 0);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    //保存录像
    T_VIDEO_KEY szVideoKey;
    pstMainCtrl->BattleToMemoryDBWithPB(szVideoKey, uiGID, BATTLE_VIDEO_TYPE_INSTANCE, *pstMsgBattleResult, 2591999);

    stAns.set_is_win(pstMsgBattleResult->result());
    CT_TRACE(("battle result %d", pstMsgBattleResult->result()));
    if (pstMsgBattleResult->result() == BATTLE_RESULT_WIN)
    {
        //触发任务
        pstMainCtrl->m_stInstanceMgr.KillEnemyTriggerTask(stPlayerOnlineData._stUserTask, stMonsterGroupConfigData);

        //新手目标
        pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, uiGID, NEWBIE_TASK_COND_3, 
                                            stMonsterGroupConfigData._uiMonsterGroupID);

        //击杀怪物奖励
        CDropItem stDropItem;

        iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroupWin(uiGID, stPlayerOnlineData._stUserInstance, stDropItem);
        if (iRet != RET_OK)
        {
            CT_WARNING(("user atk monster win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
                           stPlayerOnlineData._stUserInstance._ucNowAtInstanceType, 
                           stPlayerOnlineData._stUserInstance._usNowAtInstanceID, 
                           stPlayerOnlineData._stUserInstance._usNowPos));
        }

        //保存评分
        CInstanceScore stScore;
        MsgBattleScore* pstBattleScore = pstMsgBattleResult->mutable_battle_score();
        stScore._ucAtkScore = pstBattleScore->left_attack_score();
        stScore._ucDefScore = pstBattleScore->left_defend_score();
        stUserInstance._stScore += stScore;

        //保存录像
        stInstanceZoneDetailInfo.SaveNewKillEnemyVideo(stUserInstance._usNowPos, szVideoKey);

        //副本胜利
        if (pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stPlayerOnlineData._stUserInstance))
        {
            //首杀
            if (stInstanceZoneDetailInfo._szFirstKillRoleName.GetDataLen() == 0)
            {
                stInstanceZoneDetailInfo._szFirstKillRoleName = stPlayerBaseInfo._sRoleName;
            }
            
            //最高评分
            if (stUserInstance._stScore.GetScore() > stInstanceZoneDetailInfo._ucBestKillScore)
            {
                stInstanceZoneDetailInfo._ucBestKillScore = stUserInstance._stScore.GetScore();
                stInstanceZoneDetailInfo._szBestKillRoleName = stPlayerBaseInfo._sRoleName;
            }
        }

        //保存副本详细信息
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_INSTANCE_ZONE_DETAIL_INFO;
        stKey.m_u64ID = iInstanceDetailInfoKey;
        pstMainCtrl->UpdateData(stKey, stInstanceZoneDetailInfo, VOP_UPDATE);

        //显示给前台
        stDropItem.GetPBMsg(uiGID, *(stAns.mutable_monster_drop()));
        stDropItem.SetOssModule(OSS_MODULE_INSTANCE);
        iRet = pstMainCtrl->m_stItemMgr.DropItem(this, uiGID, stDropItem, false);
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }
        else
        {
            return RET_OK;
        }
    }

    return AnsClients(iRet);
}

//只有胜利发奖励的时候才会走到这里
int CCmdAtkInstance::CallBack(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    int iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //获取剩余的物品
    CDropItem stLeftDropItem;
    pstMainCtrl->m_stItemMgr.GetDropLeftItem(this, stLeftDropItem);

    //将物品扔在地上
    for (int i = 0; i < stLeftDropItem._astDropItem.Size(); ++i)
    {
        CDropItemData& stDropItemData = stLeftDropItem._astDropItem[i];
        //放入地表背包
        CStorageGrid stStorageGrid;
        if (RET_OK != pstMainCtrl->m_stInstanceMgr.DropToGroud(stPlayerOnlineData._stUserGroudBag, stStorageGrid, stDropItemData))
        {
            CT_WARNING(("drop to groud error"));
            continue;
        }
    }

    //副本胜利掉落
    if (!pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stPlayerOnlineData._stUserInstance))
    {
        return AnsClients(iRet);
    }
    else
    {
        CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

        //返回评分
        stAns.set_atk_grade(stUserInstance._stScore.GetAtkGrade());
        stAns.set_def_grade(stUserInstance._stScore.GetDefGrade());
        stAns.set_total_grade(stUserInstance._stScore.GetGrade());

        //设置可领奖
        stUserInstance._bHasGetInsWinBonus = false;

        //博物馆直接领取奖励
        if (CInstanceConfigData::IsMuseum(stUserInstance._ucNowAtInstanceType)) 
        {
            PBMsgHead stMsgHead;
            stMsgHead.set_msgid(ID_MAIN_GET_INS_WIN_BONUS);
            stMsgHead.set_msgtype(CSMsgDef::EMT_REQUEST);

            MsgReqGetInstanceBonus stReq;
            stReq.set_gid(uiGID);

            pstMainCtrl->m_stEncodeBuf.Clear();
            pstMainCtrl->EncodePBMsg(stReq, pstMainCtrl->m_stEncodeBuf, false);

            CTCodeStream s;
            s.Attach(pstMainCtrl->m_stEncodeBuf.GetUsedBuf(), pstMainCtrl->m_stEncodeBuf.GetUsedLen());

            //发送命令
            CCmdPBDoParam stParam((void*)pstMainCtrl, stEnpHead, stMsgHead, s);
            CCmdGetInsWinBonus* pstCmd = (CCmdGetInsWinBonus*) CT_CMDFACTORY->CreateCmd(ID_MAIN_GET_INS_WIN_BONUS);
            if (!pstCmd)
            {
                CT_ERROR((""));
            }
            else
            {
                pstCmd->bFlushCache = false;
                pstCmd->Do(&stParam);
            }
        }
    }
    
    return AnsClients(iRet);
}

int CCmdAtkInstance::AnsClients(int iRet)
{
    //保存数据
    if (RET_OK == iRet)
    {
        int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("online user %u has no base info", uiGID));
            return AnsClients(RET_SYSTEM_FAIL);
        }
        CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

        iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
        if (iIndex < 0)
        {
            CT_ERROR(("online user %u has no online data", uiGID));
            return AnsClients(RET_SYSTEM_FAIL);
        }
        CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

        stPlayerOnlineData._stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);

        //保存
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }
    
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(RET_OK);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    stAns.set_ret(iRet);
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    CT_TRACE(("CCmdAtkInstance stAns length = %d", stAns.ByteSize()));

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_LEAVE_INSTANCE, CCmdLeaveInstance);

int CCmdLeaveInstance::Do(void* pData)
{
    int iRet = 0;
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_LEAVE_INSTANCE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_LEAVE_INSTANCE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdLeaveInstance::LogicDo(int iRet)
{
    if (iRet)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user player base info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }
    
    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //清空地表
    stPlayerOnlineData._stUserGroudBag.SetEmpty();

    iRet = pstMainCtrl->m_stInstanceMgr.LeaveInstance(stPlayerOnlineData._stUserInstance);

    return AnsClients(iRet);
}

int CCmdLeaveInstance::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_SWEEP_INSTANCE, CCmdSweepInstance);

int CCmdSweepInstance::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_SWEEP_INSTANCE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_SWEEP_INSTANCE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdSweepInstance::LogicDo(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    int iNowTime = pstMainCtrl->m_iNow;

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    PREPARE_PLAYER_DETAIL_EX1_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);
    
    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo & stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];


    if (stPlayerDetailInfo._stMuseData.IsMusing())
    {
        pstMainCtrl->m_stMuseMgr.StopMuseAndNotify (stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    }

    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_23, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }
    
    //背包满了
    if (stPlayerOnlineData._stUserStorage.BagIsFull())
    {
        return AnsClients(ERROR_INSTANCE_SWEEP_BAG_FULL);
    }

    //检查是否可以扫荡
    unsigned char ucInstanceType = stReq.ins_type() & 0x7F;
    unsigned short usInstanceID = stReq.ins_id() & 0x7FFF;
    bool bNeedSaveBaseInfo = false;

    if (CInstanceConfigData::IsSecret(ucInstanceType))
    {
        CSecretInstanceConfigData stSecretConfigData;
        unsigned char ucSecID = usInstanceID & 0x7FFF;
        iRet = pstMainCtrl->m_stInstanceMgr.GetSecretConfig(ucSecID, stSecretConfigData);
        if (iRet)
        {
            return AnsClients(iRet);
        }

        if (stUserInstance._stInstanceData._stSecretInstanceData.GetMaxAtkInstanceID(ucSecID, iNowTime)
            >= stSecretConfigData._ucInstanceCount)
        {
            return AnsClients(ERROR_INSTANCE_SECRET_HAS_FINISHED);
        }

        //设置当前是打哪个副本
        usInstanceID = stUserInstance._stInstanceData._stSecretInstanceData.GetMaxAtkInstanceID(ucSecID, iNowTime) + 1;
    }

    iRet = pstMainCtrl->m_stInstanceMgr.IsCanSweep(stUserInstance, ucInstanceType, usInstanceID);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    if (CInstanceConfigData::IsMuseum(ucInstanceType))
    {
        CMuseumInstanceData& stMuseumInstanceData = stUserInstance._stInstanceData._stMuseumInstanceData;

        if (!stUserInstance._stInstanceData._stMuseumInstanceData.IsInSweep())
        {
            //检查次数是否足够
            if (stMuseumInstanceData.GetSweepCount(iNowTime) <= 0)
            {
                return AnsClients(ERROR_INSTANCE_MUSEUM_NO_SWEEP_COUNT);
            }
            
            if (usInstanceID != 1) //只能从第一个副本开始
            {
                return AnsClients(ERROR_INSTANCE_CAN_NOT_SWEEP);
            }

            stMuseumInstanceData._usNowSweepInstanceID = usInstanceID;
            pstMainCtrl->m_stInstanceMgr.GetFinishedStat(stUserInstance, ucInstanceType, stMuseumInstanceData._usMaxSweepInstanceID);
        
            //记录次数
            stMuseumInstanceData.UseSweepCount(pstMainCtrl->m_iNow);

            //下发数据
            pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);
        }
        else
        {   
            if (usInstanceID > stMuseumInstanceData._usMaxSweepInstanceID)
            {
                return AnsClients(ERROR_INSTANCE_CAN_NOT_SWEEP);
            }
            usInstanceID = stMuseumInstanceData._usNowSweepInstanceID + 1;
            stMuseumInstanceData._usNowSweepInstanceID++;
        }

        //保存数据
        stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
        bNeedSaveBaseInfo = true;
    }
    
    //进入副本
    if (CInstanceConfigData::IsSecret(ucInstanceType))
    {
        iRet = pstMainCtrl->m_stInstanceMgr.GoIntoSecret(stUserInstance, stPlayerOnlineData._stUserTask, stReq.ins_id());
    }
    else
    {
        iRet = pstMainCtrl->m_stInstanceMgr.GoIntoInstance(stUserInstance, stPlayerOnlineData._stUserTask, 
                            ucInstanceType, usInstanceID);
    }

    if (iRet)
    {
        return AnsClients(iRet);
    }

    //获取怪物队伍列表
    CInstanceMgr::T_INSTANCE_MONSTER_GROUP_IDS astMonsterGroupIDs;
    iRet = pstMainCtrl->m_stInstanceMgr.GetMonsterGroupList(stUserInstance, astMonsterGroupIDs);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    //模拟战斗胜利，计算击杀怪物奖励
    for (int i = 0; i < astMonsterGroupIDs.Size(); ++i)
    {
        //获取怪物配置
        CMonsterGroupConfigData stMonsterGroupConfigData;
        iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroup(stUserInstance, stMonsterGroupConfigData);
        if (iRet != RET_OK)
        {
            return AnsClients(iRet);
        }

        //触发任务
        pstMainCtrl->m_stInstanceMgr.KillEnemyTriggerTask(stPlayerOnlineData._stUserTask, stMonsterGroupConfigData);

        //新手目标
        pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, uiGID, NEWBIE_TASK_COND_3, 
                                                        stMonsterGroupConfigData._uiMonsterGroupID);

        //击杀怪物奖励
        CDropItem stMonsterDropItem;
        iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroupWin(uiGID, stUserInstance, stMonsterDropItem);
        if (iRet != RET_OK)
        {
            CT_WARNING(("user atk monster win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
                stPlayerOnlineData._stUserInstance._ucNowAtInstanceType, 
                stPlayerOnlineData._stUserInstance._usNowAtInstanceID, 
                stPlayerOnlineData._stUserInstance._usNowPos));
        }

        MsgSweepInstanceDropDetail* pstMsgSweepInstanceDropDetail = stAns.add_detail_drop();
        pstMsgSweepInstanceDropDetail->set_monster_group_id(astMonsterGroupIDs[i]);
        stMonsterDropItem.GetPBMsg(uiGID, *(pstMsgSweepInstanceDropDetail->mutable_drop()));

        stDropItem += stMonsterDropItem;
    }

    //模拟战斗胜利，计算副本胜利奖励
    if (!pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stUserInstance))
    {
        CT_WARNING(("sweep instance , but instance not win"));
    }
    else
    {
        CDropItem stInsDrop;
        iRet = pstMainCtrl->m_stInstanceMgr.AttackInstanceWin(uiGID, stUserInstance, stInsDrop);
        if (iRet != RET_OK)
        {
            CT_WARNING(("user atk instance win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
                stUserInstance._ucNowAtInstanceType, 
                stUserInstance._usNowAtInstanceID, 
                stUserInstance._usNowPos));
        }

        //任务触发
        if (CInstanceConfigData::INSTANCE_TYPE_MUSEUM == stUserInstance._ucNowAtInstanceType)
        {
            //扫荡了博物馆
            //trigger daily task
            pstMainCtrl->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_11);
        }
        
        stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
        bNeedSaveBaseInfo = true;

        //返回给前台
        stInsDrop.GetPBMsg(uiGID, *(stAns.mutable_drop()));

        stDropItem += stInsDrop;
    }

    stAns.set_ins_id(stUserInstance._usNowAtInstanceID);

    //退出副本
    if (CInstanceConfigData::IsSecret(ucInstanceType)) 
    {
        CSecretInstanceConfigData stSecretConfigData;
        iRet = pstMainCtrl->m_stInstanceMgr.GetSecretConfig(stUserInstance._ucSecretID, stSecretConfigData);
        if (iRet)
        {
            return AnsClients(iRet);
        }

        if (stUserInstance._usNowAtInstanceID >= stSecretConfigData._ucInstanceCount) //已经通关
        {
            stUserInstance._bHasGetInsWinBonus = false;
            stAns.set_is_sec_win(1);

            //触发任务
            CMainCtrl::m_pstMain->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_26);
        }
        else
        {
            pstMainCtrl->m_stInstanceMgr.LeaveInstance(stPlayerOnlineData._stUserInstance);
        }
    }
    else
    {
        pstMainCtrl->m_stInstanceMgr.LeaveInstance(stPlayerOnlineData._stUserInstance);
    }

    //自动售卖
    if (stReq.auto_sell() != 0)
    {
        pstMainCtrl->m_stItemMgr.AutoSell(stDropItem);
    }

    //掉落
    stDropItem.SetOssModule(OSS_MODULE_INSTANCE);
    if (RET_OK != pstMainCtrl->m_stItemMgr.DropItem(this, uiGID, stDropItem, false))
    {
        CT_WARNING(("send item error"));
    }

    //保存数据
    if (bNeedSaveBaseInfo)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }

    return iRet;
}

int CCmdSweepInstance::CallBack(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    //获取剩余的物品
    CDropItem stLeftDropItem;
    pstMainCtrl->m_stItemMgr.GetDropLeftItem(this, stLeftDropItem);
    if (stLeftDropItem._astDropItem.Size() > 0)
    {
        return AnsClients(ERROR_INSTANCE_SWEEP_BAG_FULL);
    }

    return AnsClients(iRet);
}

int CCmdSweepInstance::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(RET_OK);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    stAns.set_result(iRet);
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////

CT_REGISTER_ASYNCCMD(ID_MAIN_GET_INS_WIN_BONUS, CCmdGetInsWinBonus);

int CCmdGetInsWinBonus::Do(void* pData)
{
    int iRet = 0;
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_GET_INS_WIN_BONUS ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_GET_INS_WIN_BONUS,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}


int CCmdGetInsWinBonus::LogicDo(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no detail info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];
    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    stAns.set_ins_type(stUserInstance._ucNowAtInstanceType);
    stAns.set_ins_id(stUserInstance._usNowAtInstanceID);

    //检查
    if (CInstanceConfigData::IsSecret(stUserInstance._ucNowAtInstanceType)) //秘境有自己的领取奖励协议
    {
        return AnsClients(RET_SYS_ERROR);
    }
    
    if (!pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stUserInstance))
    {
        return AnsClients(ERROR_INSTANCE_IS_NOT_ACCOMPLISH);
    }

    if (stUserInstance._bHasGetInsWinBonus)
    {
        return AnsClients(ERROR_INSTANCE_HAS_GET_BONUS);
    }
    
    //副本胜利奖励
    CDropItem stDropItem;
    iRet = pstMainCtrl->m_stInstanceMgr.AttackInstanceWin(uiGID, stPlayerOnlineData._stUserInstance, stDropItem);
    if (iRet != RET_OK)
    {
        CT_WARNING(("user atk instance win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
            stPlayerOnlineData._stUserInstance._ucNowAtInstanceType, 
            stPlayerOnlineData._stUserInstance._usNowAtInstanceID, 
            stPlayerOnlineData._stUserInstance._usNowPos));
    }

    //触发任务
    int iTaskInstanceId = CONST_TASK_INSTANCE_ID_MOD * stPlayerOnlineData._stUserInstance._ucNowAtInstanceType + stPlayerOnlineData._stUserInstance._usNowAtInstanceID;
    CUserTask& stUserTask = stPlayerOnlineData._stUserTask;
    pstMainCtrl->m_stTaskMgr.TriggerFinishInstance(stUserTask, iTaskInstanceId, 1);

    //博物馆跑马灯
    if (CInstanceConfigData::IsMuseum(stUserInstance._ucNowAtInstanceType))
    {
        //   【玩家昵称】通关【博物馆第几层】，获得秘宝【秘宝名称】！
        unsigned short usTreasureID = 0;
        for (int i = 0; i < stDropItem._astDropItem.Size(); ++i)
        {
            if (ITEM_TYPE_TREASURE == stDropItem._astDropItem[i]._ucItemType)
            {
                usTreasureID = stDropItem._astDropItem[i]._usItemConfigID;

                if (!pstMainCtrl->m_stTreasureMgr.IsRoleGetTreasure(usTreasureID, stPlayerDetailInfo))
                {
                    MsgTips stTips;
                    stTips.set_type(1008);
                    stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
                    stTips.add_tip_argument(CTStringUtils::IntToString(stUserInstance._usNowAtInstanceID));
                    stTips.add_tip_argument(CTStringUtils::IntToString(usTreasureID));

                    CMainCtrl::m_pstMain->SendOnlineTips(stTips);       
                }

                break;
            }
        }
    }

    //返回给前台
    CDropItem stDirectDropItems;
    for (int i = 0; i < stDropItem._astDropItem.Size(); ++i)
    {        
        CDropItemData& stDropItemData = stDropItem._astDropItem[i];

        CT_WARNING(("%d, %d, %d", stDropItemData._ucItemType, stDropItemData._usItemConfigID, stDropItemData._iItemCount));

        switch(stDropItemData._ucItemType)
        {
        case ITEM_TYPE_EXP:
        case ITEM_TYPE_LEVEL_EXP:
        case ITEM_TYPE_CLAN_EXP:
            {
                stDirectDropItems.Drop(stDropItemData); 
            }
            break;
        default:
            {
                CItemConfigData stItemConfigData;
                if (RET_OK != pstMainCtrl->m_stItemMgr.GetConfig(stDropItemData._ucItemType,
                    stDropItemData._usItemConfigID, stItemConfigData))
                {
                    CT_WARNING((""));
                    continue;
                }

                if (stItemConfigData._iUseGrid == 0 && true != stItemConfigData._bCanFillInGroundBag)
                {
                    stDirectDropItems.Drop(stDropItemData);
                    continue;
                }
                
                //放入地表背包
                CStorageGrid stStorageGrid;
                if (RET_OK != pstMainCtrl->m_stInstanceMgr.DropToGroud(stPlayerOnlineData._stUserGroudBag, stStorageGrid, stDropItemData))
                {
                    CT_WARNING(("drop to groud error"));
                    continue;
                }
            }
            break;
        }
    }

    //显示地表内容
    CStorageMgr::T_STORAGE_GRIDS astStorageGrid;
    pstMainCtrl->m_stStorageMgr.GetBagList(stPlayerOnlineData._stUserGroudBag, astStorageGrid);
    for (int i = 0; i < astStorageGrid.Size(); ++i)
    {
        //显示给前台
        MsgGridItemInfo* pstInstanceDrop = stAns.add_instance_drop_to_groud();
        pstInstanceDrop->set_item_store_pos(astStorageGrid[i]._stKey._usStorePos);
        pstInstanceDrop->set_item_type(astStorageGrid[i]._stKey._ucItemType);
        pstInstanceDrop->set_item_config_id(astStorageGrid[i]._stKey._uiItemID);
        pstInstanceDrop->set_item_count(astStorageGrid[i]._shCount);
        if (astStorageGrid[i]._stKey._ucItemType == ITEM_TYPE_CLAN_EXP 
            || astStorageGrid[i]._stKey._ucItemType == ITEM_TYPE_CLAN_SILVER)
        {
            pstInstanceDrop->set_item_aux_info(CTStringUtils::Uint64ToString(astStorageGrid[i]._iPosValue, 10));
        }
    }

    //返回前台信息
    stDirectDropItems.GetPBMsg(uiGID, *(stAns.mutable_instance_drop()));
    stDirectDropItems.SetOssModule(OSS_MODULE_INSTANCE);
    if (RET_OK != pstMainCtrl->m_stItemMgr.DropItem(this, uiGID, stDirectDropItems, false))
    {
        CT_WARNING(("send item error"));
    }

    //设置奖励已领取
    stUserInstance._bHasGetInsWinBonus = true;

    //发送副本信息
    pstMainCtrl->m_stInstanceMgr.SendInstanceInfoToFront(stPlayerOnlineData._stUserInstance, 
        stPlayerOnlineData._stUserTask, stMsgHead, stEnpHead);

    //发送分数
    //pstMainCtrl->m_stInstanceMgr.SendInstanceGradeToFront(stUserInstance, stPlayerOnlineData._stUserTask, stMsgHead, stEnpHead);

    //保存数据
    stPlayerOnlineData._stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);

    //保存
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_BASE_INFO;
    stKey.m_u64ID = stPlayerBaseInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);

    return iRet;
}


//只有胜利发奖励的时候才会走到这里
int CCmdGetInsWinBonus::CallBack(int iRet)
{
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    int iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //获取剩余的物品
    CDropItem stLeftDropItem;
    pstMainCtrl->m_stItemMgr.GetDropLeftItem(this, stLeftDropItem);

    //将物品扔在地上
    for (int i = 0; i < stLeftDropItem._astDropItem.Size(); ++i)
    {
        CDropItemData& stDropItemData = stLeftDropItem._astDropItem[i];
        
        CT_WARNING(("%d, %d, %d", stDropItemData._ucItemType, stDropItemData._usItemConfigID, stDropItemData._iItemCount));

        //放入地表背包
        CStorageGrid stStorageGrid;
        if (RET_OK != pstMainCtrl->m_stInstanceMgr.DropToGroud(stPlayerOnlineData._stUserGroudBag, stStorageGrid, stDropItemData))
        {
            CT_WARNING(("drop to groud error"));
            continue;
        }     

        //显示给前台
        MsgGridItemInfo* pstInstanceDrop = stAns.add_instance_drop_to_groud();
        pstInstanceDrop->set_item_store_pos(stStorageGrid._stKey._usStorePos);
        pstInstanceDrop->set_item_type(stDropItemData._ucItemType);
        pstInstanceDrop->set_item_config_id(stDropItemData._usItemConfigID);
        pstInstanceDrop->set_item_count(stDropItemData._iItemCount);
        pstInstanceDrop->set_item_aux_info(CTStringUtils::Uint64ToString(stDropItemData._iData1, 10));   //告诉前台家族额外增加的奖励千分比
    }

    return AnsClients(iRet);
}

int CCmdGetInsWinBonus::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, bFlushCache);

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_INS_OPT, CCmdInstanceOpt);

int CCmdInstanceOpt::Do(void* pData)
{
    int iRet = 0;
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_INS_OPT ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_INS_OPT,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdInstanceOpt::LogicDo(int iRet)
{
    if (RET_OK != iRet)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    //PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    /*
    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];
    */

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];
    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    int iNowTime = CMainCtrl::m_pstMain->m_iNow;
    unsigned char ucOpt = stReq.opt();
    stAns.set_gid(uiGID);
    stAns.set_opt(stReq.opt());

    bool bNeedSaveBaseData = false;
    //bool bNeedSaveDetailData = false;

    switch (ucOpt)
    {
    case 1: // 重置精英副本攻打次数
        {
            unsigned char ucInstanceType = stReq.ins_type();
            if (!CInstanceConfigData::IsElite(ucInstanceType))
            {
                return AnsClients(ERROR_INSTANCE_ELITE_NOT_ELITE);
            }

            CEliteInstanceAtkStat& stEliteAtkStat = stUserInstance._stInstanceData._stEliteAtkStat;

            //获取攻打的副本个数
            int iIndex = ucInstanceType - CInstanceConfigData::INSTANCE_TYPE_ELITE_BEGIN;
            int iCount = stEliteAtkStat.GetHasAtkedCount(iIndex, pstMainCtrl->m_iNow);
            if (iCount <= 0)
            {
                return AnsClients(ERROR_INSTANCE_ELITE_CAN_NOT_ATKED);
            }

            int iMaxResetCount = 0;
            iRet = pstMainCtrl->m_stVipMgr.GetVipDestNum(stPlayerBaseInfo._chVipLevel, VIP_MODULE_ID_7, iMaxResetCount);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }
            
            int iHasBuyResetCount = stEliteAtkStat.GetHasBuyResetCount(iIndex, iNowTime);
            if (iHasBuyResetCount >= iMaxResetCount)
            {
                return AnsClients(ERROR_INSTANCE_ELITE_RESET_TOO_MANY_TIMES);
            }

            int iPrice = 0;
            switch (iHasBuyResetCount)
            {
            case 0:
                iPrice = 10;
                break;
            case 1: 
                iPrice = 30;
                break;
            case 2:
                iPrice = 50;
                break;
            default:
                iPrice = 50;
                break;
            }

            int iNeedGold = iPrice * iCount;
            iRet = pstMainCtrl->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_14, iNeedGold);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }
            
            //增加次数
            stEliteAtkStat.AddHasBuyResetCount(iIndex, iNowTime);
            
            //重置副本
            stEliteAtkStat.ClearAtkStat(iIndex);

            //保存数据
            stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
            
            pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);
            bNeedSaveBaseData = true;
        }
        break;
    case 2: //博物馆信息
        {
            //检查系统是否开启
            if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_21, stPlayerBaseInfo, stPlayerOnlineData))
            {
                return AnsClients(ERROR_SYS_NOT_OPEN);
            }

            CMuseumRank& stMuseumRank = pstMainCtrl->m_stInstanceMgr._stMuseumRank;
            for (int i = 0; i < stMuseumRank.Size(); ++i)
            {
                CInstanceMuseumRankData& stMuseumRankData = stMuseumRank[i];

                int iIndex = pstMainCtrl->m_stPlayerSnsCommInfoHash.HashFind(stMuseumRankData._uiGID);
                if (iIndex < 0)
                {
                    CT_WARNING(("%u", stMuseumRankData._uiGID));
                    continue;
                }
                CPlayerSnsCommInfo& stPlayerSnsCommInfo = pstMainCtrl->m_stPlayerSnsCommInfoHash[iIndex];

                CInstanceConfigData stConfigData;
                iRet = pstMainCtrl->m_stInstanceMgr.GetConfigData(CInstanceConfigData::INSTANCE_TYPE_MUSEUM, stMuseumRankData._usMaxInstanceID, stConfigData);
                if (iRet)
                {
                    CT_WARNING(("%d", stMuseumRankData._usMaxInstanceID));
                    continue;
                }
                
                MsgMuseumRankData *pstMsgMuseumRankData = stAns.add_museum_rank();
                pstMsgMuseumRankData->set_rank(i + 1);
                pstMsgMuseumRankData->set_gid(stMuseumRankData._uiGID);
                pstMsgMuseumRankData->set_name(stPlayerSnsCommInfo._sRoleName());
                pstMsgMuseumRankData->set_instance_id(stMuseumRankData._usMaxInstanceID);
                pstMsgMuseumRankData->set_enemy_pos(stMuseumRankData._ucMaxEnemyPos);
                pstMsgMuseumRankData->set_total_enemy(stConfigData._astMonsterGroupIDs.Size());
            }   

            stAns.set_has_buy_museum_sweep_count(stUserInstance._stInstanceData._stMuseumInstanceData.GetHasBuySweepCount(iNowTime));
            stAns.set_museum_left_sweep_count(stUserInstance._stInstanceData._stMuseumInstanceData.GetSweepCount(pstMainCtrl->m_iNow));
        }
        break;
    case 3:// 购买博物馆扫荡次数
        {
            //检查系统是否开启
            if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_21, stPlayerBaseInfo, stPlayerOnlineData))
            {
                return AnsClients(ERROR_SYS_NOT_OPEN);
            }

            int iNeedGold = 0;
            int iMaxCanBuyCountCount = 0;
            iRet = pstMainCtrl->m_stVipMgr.GetVipDestNum(stPlayerBaseInfo._chVipLevel, VIP_MODULE_ID_6, iMaxCanBuyCountCount);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }

            iRet = stUserInstance._stInstanceData._stMuseumInstanceData.GetBuySweepCountPrice(pstMainCtrl->m_iNow, iNeedGold, iMaxCanBuyCountCount);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }
            
            iRet = pstMainCtrl->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_13, iNeedGold);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }
            
            //增加购买次数
            stUserInstance._stInstanceData._stMuseumInstanceData.AddBuySweepCount(pstMainCtrl->m_iNow);

            stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
            bNeedSaveBaseData = true;
            pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);

            stAns.set_museum_left_sweep_count(stUserInstance._stInstanceData._stMuseumInstanceData.GetSweepCount(pstMainCtrl->m_iNow));
        }
        break;
    case 4: //获取副本是否攻打过的信息
        {
            unsigned char ucInstanceType = stReq.ins_type();

            if (CInstanceConfigData::IsElite(ucInstanceType))
            {
                unsigned short usAccTo = 0;
                pstMainCtrl->m_stInstanceMgr.GetFinishedStat(stUserInstance, ucInstanceType, usAccTo);

                for (unsigned short i = 1; i <= usAccTo; ++i)
                {
                    if (stUserInstance._stInstanceData._stEliteAtkStat.IsAtkWin(ucInstanceType - CInstanceConfigData::INSTANCE_TYPE_ELITE_BEGIN,
                                                i, pstMainCtrl->m_iNow))
                    {
                        stAns.add_has_atked_ins_id(i);
                    }
                }

                int iMaxResetCount = 0;
                iRet = pstMainCtrl->m_stVipMgr.GetVipDestNum(stPlayerBaseInfo._chVipLevel, VIP_MODULE_ID_7, iMaxResetCount);
                if (RET_OK != iRet)
                {
                    return AnsClients(iRet);
                }

                stAns.set_can_reset_count(iMaxResetCount - stUserInstance._stInstanceData._stEliteAtkStat.GetHasBuyResetCount(ucInstanceType - CInstanceConfigData::INSTANCE_TYPE_ELITE_BEGIN, pstMainCtrl->m_iNow));
                stAns.set_has_reset_elite_count(stUserInstance._stInstanceData._stEliteAtkStat.GetHasBuyResetCount(ucInstanceType - CInstanceConfigData::INSTANCE_TYPE_ELITE_BEGIN, pstMainCtrl->m_iNow));
            }
        }
        break;
    case 5: // 获取星级评分礼包状态
        {
            int iBonusID = stReq.bonus_id();

            CInstanceGradeBonusConfigData stConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr._stInstanceGradeBonusConfig.GetConfig(iBonusID, stConfigData);
            if (iRet)
            {
                return AnsClients(iRet);
            }
            
            //获取总评分
            int iTotalGrade = 0;
            for (int i = 0; i < stConfigData._ashIncludeInstanceID.Size(); ++i)
            {
                unsigned char ucGrade = 0;
                stUserInstance._stInstanceData._stMainInstanceGrad.GetGrad(stConfigData._ashIncludeInstanceID[i], ucGrade);
                iTotalGrade += ucGrade;
            }
            stAns.set_now_total_grade(iTotalGrade);
            
            //获取是否已经领取过的信息
            for (int i = 0; i < stConfigData._astGradeConfigs.Size(); ++i)
            {
                MsgInstanceGradeBonusInfo* pstMsgInstanceGradeBonusInfo = stAns.add_grade_binus_info();
                pstMsgInstanceGradeBonusInfo->set_need_grade(stConfigData._astGradeConfigs[i]._usNeedGrade);
                pstMsgInstanceGradeBonusInfo->set_grade_gift_id(stConfigData._astGradeConfigs[i]._usGiftConfigID);
                pstMsgInstanceGradeBonusInfo->set_has_get(stUserInstance._stInstanceData._stGradeBonusStat.IsSet(iBonusID, i));
            }
        }
        break;
    case 6: // 领取星级评分礼包
        {
            int iBonusID = stReq.bonus_id();
            unsigned char ucPos = stReq.bonus_pos();

            CInstanceGradeBonusConfigData stConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr._stInstanceGradeBonusConfig.GetConfig(iBonusID, stConfigData);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            if (ucPos >= stConfigData._astGradeConfigs.Size())
            {
                return AnsClients(RET_SYS_ERROR);
            }

            //获取是否已经领取过的信息
            if (stUserInstance._stInstanceData._stGradeBonusStat.IsSet(iBonusID, ucPos))
            {
                return AnsClients(ERROR_INSTANCE_HAS_GET_GRADE_BONUS);
            }

            //获取总评分
            int iTotalGrade = 0;
            for (int i = 0; i < stConfigData._ashIncludeInstanceID.Size(); ++i)
            {
                unsigned char ucGrade = 0;
                stUserInstance._stInstanceData._stMainInstanceGrad.GetGrad(stConfigData._ashIncludeInstanceID[i], ucGrade);
                iTotalGrade += ucGrade;
            }
            stAns.set_now_total_grade(iTotalGrade);

            //检查评分是否足够
            if (iTotalGrade < stConfigData._astGradeConfigs[ucPos]._usNeedGrade)
            {
                return AnsClients(ERROR_INSTANCE_LESS_GRADE);
            }

            //检查背包是否已满
            if (stPlayerOnlineData._stUserStorage.BagIsFull())
            {
                return AnsClients(ERROR_STORAGE_BAG_IS_FULL);
            }

            //设置领取状态
            stUserInstance._stInstanceData._stGradeBonusStat.Set(iBonusID, ucPos);

            //发放礼包            
            CDropItemData stDropItemData;
            stDropItemData._ucItemType = ITEM_TYPE_GIFT;
            stDropItemData._usItemConfigID = stConfigData._astGradeConfigs[ucPos]._usGiftConfigID;
            stDropItemData._iItemCount = 1;
            stDropItemData._iData1 = ADD_GIFT_BAG;
            
            stAns.set_gift_id(stDropItemData._usItemConfigID);

            CDropItem stDropItem;
            stDropItem.Drop(stDropItemData);
            stDropItem.SetOssModule(OSS_MODULE_INSTANCE);
            pstMainCtrl->m_stItemMgr.DropItem(NULL, uiGID, stDropItem, false);

            //保存数据
            stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
            bNeedSaveBaseData = true;
            
        }
        break;
    case 7: //获取所有副本信息
        {
            pstMainCtrl->m_stInstanceMgr.SendInstanceGradeToFront(stPlayerOnlineData._stUserInstance, stPlayerOnlineData._stUserTask, stMsgHead, stEnpHead);
            pstMainCtrl->m_stInstanceMgr.SendInstanceInfoToFront(stPlayerOnlineData._stUserInstance, stPlayerOnlineData._stUserTask, stMsgHead, stEnpHead);
        }
        break;
    default:
        return AnsClients(RET_SYS_ERROR);
    }

    //保存数据
    if (bNeedSaveBaseData)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }
   
    return AnsClients(iRet);
}

int CCmdInstanceOpt::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true);

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_INS_SECRET, CCmdSecretInstance);

int CCmdSecretInstance::Do(void* pData)
{
    int iRet = 0;
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_INS_SECRET ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_INS_SECRET,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    return LogicDo(RET_OK);
}

int CCmdSecretInstance::LogicDo(int iRet)
{
    if (RET_OK != iRet)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);
    PREPARE_PLAYER_DETAIL_EX1_INFO(this, uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no base info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no detail info", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];
    CUserInstance& stUserInstance = stPlayerOnlineData._stUserInstance;

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_16, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    //副本详细信息准备
    if (stReq.sec_id() == 0)
    {
        for (unsigned char i = 1; i <= MAX_INSTANCE_SECRET_CONFIG_COUNT; ++i)
        {
            CSecretInstanceConfigData stSecretConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr._stSecretInstanceConfig.GetConfig(i, stSecretConfigData);
            if (RET_OK != iRet)
            {
                CT_WARNING(("%d", i));
                continue;
            }

            for (unsigned short usTmp = 1; usTmp <= stSecretConfigData._ucInstanceCount; ++usTmp)
            {
                PREPARE_INSTANCE_ZONE_DETAIL_INFO(this, CInstanceZoneDetailInfo::GetKey(stSecretConfigData._ucInstanceType, usTmp));
            }
        }
    }
    else
    {
        CSecretInstanceConfigData stSecretConfigData;
        iRet = pstMainCtrl->m_stInstanceMgr._stSecretInstanceConfig.GetConfig(stReq.sec_id(), stSecretConfigData);
        if (RET_OK != iRet)
        {
            CT_WARNING(("%d", stReq.sec_id()));
        }
        else
        {
            for (unsigned short usTmp = 1; usTmp <= stSecretConfigData._ucInstanceCount; ++usTmp)
            {
                PREPARE_INSTANCE_ZONE_DETAIL_INFO(this, CInstanceZoneDetailInfo::GetKey(stSecretConfigData._ucInstanceType, usTmp));
            }
        }
    }

    int iNowTime = CMainCtrl::m_pstMain->m_iNow;
    unsigned char ucOpt = stReq.opt();
    stAns.set_gid(uiGID);
    stAns.set_opt(stReq.opt());

    bool bNeedSaveBaseData = false;

    switch (ucOpt)
    {
    case 1: // 获取秘境信息
        {
            unsigned char ucSecID = stReq.sec_id();
            pstMainCtrl->m_stInstanceMgr.GetSecretInstanceInfo(stPlayerOnlineData._stUserInstance, stPlayerOnlineData._stUserTask, ucSecID, stPlayerBaseInfo._chVipLevel, *(stAns.mutable_sec_info()));
        }
        break;
    case 2: //攻打秘境
        {
            unsigned char ucSecID = stReq.sec_id();

            CSecretInstanceConfigData stSecretConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr.GetSecretConfig(ucSecID, stSecretConfigData);
            if (iRet)
            {
                return AnsClients(iRet);
            }
            
            if (stUserInstance._ucSecretID != ucSecID) //新进入秘境
            {
                //清空地表
                stPlayerOnlineData._stUserGroudBag.SetEmpty();
            }

            //进入
            iRet = pstMainCtrl->m_stInstanceMgr.GoIntoSecret(stUserInstance, stPlayerOnlineData._stUserTask, ucSecID);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            //准备副本详细信息数据
            int iKey = CInstanceZoneDetailInfo::GetKey(stUserInstance._ucNowAtInstanceType, stUserInstance._usNowAtInstanceID);
            PREPARE_INSTANCE_ZONE_DETAIL_INFO(this, iKey);
            iIndex = pstMainCtrl->m_stInstanceZoneDetailInfoHash.HashFind(iKey);
            if (iIndex < 0)
            {
                CT_ERROR((""));
                return AnsClients(RET_SYS_ERROR);
            }
            CInstanceZoneDetailInfo& stInstanceZoneDetailInfo = pstMainCtrl->m_stInstanceZoneDetailInfoHash[iIndex];

            //获取怪物列表
            CMonsterGroupConfigData stMonsterGroupConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroup(stPlayerOnlineData._stUserInstance, stMonsterGroupConfigData);
            if (iRet != RET_OK)
            {
                return AnsClients(iRet);
            }
            
            //攻打
            MsgBattleResult* pstMsgBattleResult = stAns.mutable_battle_result();
            if (pstMsgBattleResult && stReq.has_ext_info())
            {
                (*pstMsgBattleResult->mutable_battle_ext_info()) = stReq.ext_info();
            }
            iRet = pstMainCtrl->m_stBattleMgr.DealBattle(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, 
                stMonsterGroupConfigData, *pstMsgBattleResult, 0);
            if (iRet != RET_OK)
            {
                return AnsClients(iRet);
            }

            //保存录像
            T_VIDEO_KEY szVideoKey;
            pstMainCtrl->BattleToMemoryDBWithPB(szVideoKey, uiGID, BATTLE_VIDEO_TYPE_INSTANCE, *pstMsgBattleResult, 2591999);

            stAns.set_now_atk_pos(stPlayerOnlineData._stUserInstance._usNowAtInstanceID);
            stAns.set_is_win(pstMsgBattleResult->result());

            bool bSecHasFinished = false;
            
            if (pstMsgBattleResult->result() == BATTLE_RESULT_WIN)
            {
                bSecHasFinished = (stUserInstance._usNowAtInstanceID >= stSecretConfigData._ucInstanceCount);

                //触发任务
                pstMainCtrl->m_stInstanceMgr.KillEnemyTriggerTask(stPlayerOnlineData._stUserTask, stMonsterGroupConfigData);

                //新手目标
                pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, uiGID, NEWBIE_TASK_COND_3, 
                                    stMonsterGroupConfigData._uiMonsterGroupID);

                //击杀怪物奖励
                CDropItem stMonsterDropItem;

                iRet = pstMainCtrl->m_stInstanceMgr.AttackMonsterGroupWin(uiGID, stPlayerOnlineData._stUserInstance, stMonsterDropItem);
                if (iRet != RET_OK)
                {
                    CT_WARNING(("user atk monster win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
                        stPlayerOnlineData._stUserInstance._ucNowAtInstanceType, 
                        stPlayerOnlineData._stUserInstance._usNowAtInstanceID, 
                        stPlayerOnlineData._stUserInstance._usNowPos));
                }

                //显示给前台
                stMonsterDropItem.GetPBMsg(uiGID, *(stAns.mutable_ins_drop()));

                if (!pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stPlayerOnlineData._stUserInstance)) //秘境副本只会有一堆怪
                {
                    CT_WARNING(("sec id %d, instance id %d", ucSecID, stPlayerOnlineData._stUserInstance._usNowAtInstanceID));
                    return AnsClients(RET_SYS_ERROR);
                }

                //保存评分
                CInstanceScore stScore;
                MsgBattleScore* pstBattleScore = pstMsgBattleResult->mutable_battle_score();
                stScore._ucAtkScore = pstBattleScore->left_attack_score();
                stScore._ucDefScore = pstBattleScore->left_defend_score();
                stUserInstance._stScore += stScore;

                //返回评分
                stAns.set_atk_grade(stUserInstance._stScore.GetAtkGrade());
                stAns.set_def_grade(stUserInstance._stScore.GetDefGrade());
                stAns.set_total_grade(stUserInstance._stScore.GetGrade());

                //保存录像
                stInstanceZoneDetailInfo.SaveNewKillEnemyVideo(1, szVideoKey);

                //首杀
                if (stInstanceZoneDetailInfo._szFirstKillRoleName.GetDataLen() == 0)
                {
                    stInstanceZoneDetailInfo._szFirstKillRoleName = stPlayerBaseInfo._sRoleName;
                }

                //最高评分
                if (stUserInstance._stScore.GetScore() > stInstanceZoneDetailInfo._ucBestKillScore)
                {
                    stInstanceZoneDetailInfo._ucBestKillScore = stUserInstance._stScore.GetScore();
                    stInstanceZoneDetailInfo._szBestKillRoleName = stPlayerBaseInfo._sRoleName;
                }

                //保存副本详细信息
                CVarObjectKey stKey;
                stKey.m_chDataType = DT_INSTANCE_ZONE_DETAIL_INFO;
                stKey.m_u64ID = stInstanceZoneDetailInfo.GetKey();
                pstMainCtrl->UpdateData(stKey, stInstanceZoneDetailInfo, VOP_UPDATE);

                //通关后才可以领通关奖励
                stUserInstance._bHasGetInsWinBonus = !bSecHasFinished;

                //秘境通关奖励，一般不会配，所以不用做掉落，只做结果记录用
                CDropItem stSecDropItem;
                iRet = pstMainCtrl->m_stInstanceMgr.AttackInstanceWin(uiGID, stPlayerOnlineData._stUserInstance, stSecDropItem);
                if (iRet != RET_OK)
                {
                    CT_WARNING(("user atk instance win , but give bonus error, ret %d, instance (%d, %d, %d)", iRet, 
                        stPlayerOnlineData._stUserInstance._ucNowAtInstanceType, 
                        stPlayerOnlineData._stUserInstance._usNowAtInstanceID, 
                        stPlayerOnlineData._stUserInstance._usNowPos));
                }

                //物品掉落
                stMonsterDropItem.SetOssModule(OSS_MODULE_INSTANCE);
                pstMainCtrl->m_stItemMgr.DropItem(NULL, uiGID, stMonsterDropItem, false);
                
                //触发任务
                int iTaskInstanceId = CONST_TASK_INSTANCE_ID_MOD * stPlayerOnlineData._stUserInstance._ucNowAtInstanceType + stPlayerOnlineData._stUserInstance._usNowAtInstanceID;
                CUserTask& stUserTask = stPlayerOnlineData._stUserTask;
                pstMainCtrl->m_stTaskMgr.TriggerFinishInstance(stUserTask, iTaskInstanceId, 1);
                if (bSecHasFinished)
                {
                    CMainCtrl::m_pstMain->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_26);
                }
                
                //发送副本信息
                stAns.set_is_sec_win(bSecHasFinished ? 1 : 0);
                pstMainCtrl->m_stInstanceMgr.SendInstanceInfoToFront(stPlayerOnlineData._stUserInstance, 
                    stPlayerOnlineData._stUserTask, stMsgHead, stEnpHead);
                
                //保存数据
                stPlayerOnlineData._stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
                bNeedSaveBaseData = true;

                //跑马灯
                if (bSecHasFinished)
                {
                    MsgTips stTips;
                    stTips.set_type(1046);

                    stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
                    stTips.add_tip_argument(CTStringUtils::IntToString(stSecretConfigData._ucInstanceType));
                    stTips.add_tip_argument(CTStringUtils::IntToString(stUserInstance._usNowAtInstanceID));
                    stTips.add_tip_argument(CTStringUtils::IntToString(stSecretConfigData._ucHardSecretType == 0));
                    
                    CMainCtrl::m_pstMain->SendOnlineTips(stTips);
                }
            }
        }
        break;
    case 3: // 领取秘境通关奖励
        {
            if (!CInstanceConfigData::IsSecret(stUserInstance._ucNowAtInstanceType)
                || stUserInstance._ucSecretID == 0)
            {
                return AnsClients(RET_SYS_ERROR);
            }

            if (!pstMainCtrl->m_stInstanceMgr.IsInstanceWin(stUserInstance))
            {
                return AnsClients(ERROR_INSTANCE_IS_NOT_ACCOMPLISH);
            }

            CSecretInstanceConfigData stSecretConfigData;
            iRet = pstMainCtrl->m_stInstanceMgr.GetSecretConfig(stUserInstance._ucSecretID, stSecretConfigData);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            if (stUserInstance._usNowAtInstanceID < stSecretConfigData._ucInstanceCount)
            {
                return AnsClients(ERROR_INSTANCE_SECRET_NOT_FINISHED);
            }
            
            if (stUserInstance._bHasGetInsWinBonus)
            {
                return AnsClients(ERROR_INSTANCE_HAS_GET_BONUS);
            }
            stUserInstance._bHasGetInsWinBonus = true;


            //打开显示宝箱
            CDropItem stGiftDropItem;
            GetCardInfo(stSecretConfigData._uiShowBoxID, stGiftDropItem, *(stAns.mutable_card2_drop()));
            GetCardInfo(stSecretConfigData._uiShowBoxID, stGiftDropItem, *(stAns.mutable_card3_drop()));

            //打开掉落宝箱
            stGiftDropItem.Clear();
            GetCardInfo(stSecretConfigData._uiDropBoxID, stGiftDropItem, *(stAns.mutable_card1_drop()));

            CDropItem stDirectDropItems;
            for (int i = 0; i < stGiftDropItem._astDropItem.Size(); ++i)
            {
                CDropItemData& stDropItemData = stGiftDropItem._astDropItem[i];
                switch(stDropItemData._ucItemType)
                {
                case ITEM_TYPE_EXP:
                case ITEM_TYPE_LEVEL_EXP:
                case ITEM_TYPE_CLAN_EXP:
                    {
                        stDirectDropItems.Drop(stDropItemData); 
                    }
                    break;
                default:
                    {
                        //放入地表背包
                        CStorageGrid stStorageGrid;
                        if (RET_OK != pstMainCtrl->m_stInstanceMgr.DropToGroud(stPlayerOnlineData._stUserGroudBag, stStorageGrid, stDropItemData))
                        {
                            CT_WARNING(("drop to groud error"));
                            continue;
                        }

                        //显示给前台
                        MsgGridItemInfo* pstInstanceDrop = stAns.add_drop_to_groud();
                        pstInstanceDrop->set_item_store_pos(stStorageGrid._stKey._usStorePos);
                        pstInstanceDrop->set_item_type(stDropItemData._ucItemType);
                        pstInstanceDrop->set_item_config_id(stDropItemData._usItemConfigID);
                        pstInstanceDrop->set_item_count(stDropItemData._iItemCount);
                        pstInstanceDrop->set_item_aux_info(CTStringUtils::Uint64ToString(stDropItemData._iData1, 10));
                    }
                    break;
                }
            }
            stDirectDropItems.GetPBMsg(uiGID, *(stAns.mutable_sec_drop()));
            pstMainCtrl->m_stItemMgr.DropItem(NULL, uiGID, stDirectDropItems, false);
        }
        break;
    case 4: // 重置秘境
        {
            unsigned char ucSecID = stReq.sec_id();

#ifndef _DEBUG
            //检查
            if (!stPlayerOnlineData._stUserInstance._stInstanceData._stSecretInstanceData.IsCanReset(ucSecID, MAX_CAN_RESET_SECRET_COUNT, iNowTime))
            {
                return AnsClients(ERROR_INSTANCE_SECRET_CAN_NOT_RESET);
            }
#endif
            
            //扣除金币
            iRet = pstMainCtrl->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_15, INSTANCE_RESET_SECRET_COST_GOLD);
            if (RET_OK != iRet)
            {
                return AnsClients(iRet);
            }

            //重置
            stPlayerOnlineData._stUserInstance._stInstanceData._stSecretInstanceData.Reset(ucSecID, iNowTime);

            //保存数据
            stPlayerOnlineData._stUserInstance.GetData(stPlayerBaseInfo._stInstanceData);
            bNeedSaveBaseData = true;

            //下发数据
            pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);
        }
        break;
    default:
        return AnsClients(RET_SYS_ERROR);
    }

    //保存数据
    if (bNeedSaveBaseData)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }
   
    return AnsClients(RET_OK);
}

int CCmdSecretInstance::GetCardInfo(unsigned int uiBoxID, CDropItem& stGiftDropItem, ::google::protobuf::RepeatedPtrField<MsgGridItemInfo>& stInfos)
{
    int iRet = 0;
    stGiftDropItem.Clear();

    iRet = pstMainCtrl->m_stItemMgr.GetGiftItem(uiBoxID, uiGID, stGiftDropItem, false);
    if (iRet)
    {
        CT_WARNING(("get gift item ret %d, %d", iRet, uiBoxID));
    }
    else
    {
        stGiftDropItem.GetPBMsg(uiGID, stInfos);
    }

    return 0;
}

int CCmdSecretInstance::AnsClients(int iRet)
{
    stMsgHead.set_msgret(RET_OK);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    stAns.set_ret(iRet);

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true);

    return Done(iRet);
}


